/**
 * 版权所有 @鸿名物联 
 * 未经授权，禁止侵权和商业，违法必究
 * 联系QQ：2224313811 
 * 
 */
package com.lp.controller.iot;

import com.lp.bo.IotNodeInfoBO;
import com.lp.bo.IotSensorInfoBO;
import com.lp.bo.UserInfoBO;
import com.lp.cache.CacheName;
import com.lp.cache.ProCacheUtil;
import com.lp.common.Code;
import com.lp.common.CodeIot;
import com.lp.common.Constants;
import com.lp.common.RequestURLIOT;
import com.lp.controller.BaseController;
import com.lp.mqtt.MqttService;
import com.lp.service.IotSensorInfoService;
import com.lp.util.ObjectUtil;
import com.lp.util.ResultMapUtils;
import com.lp.util.iot.ProtocolUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.Map;


@Controller
public class IotSensorInfoController extends BaseController {

	
	@Autowired
	private IotSensorInfoService iotSensorInfoService ;
	
	/**
	 * 检索
	 * @param response
	 * @param 
	 * @return
	 */
	@RequestMapping(method = RequestMethod.POST, value = RequestURLIOT.SensorInfo.SENSOR_INFO_PAGE)
	public ModelAndView selectPage(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestBody IotSensorInfoBO obj,
			@RequestParam(required=false) Integer pageSize ,
			@RequestParam Integer paged ) {
		Map<String, Object> resultMap = getResultMap();
		try {
			UserInfoBO user = getUserInfoByUserKey(userKey);
			if( verifyUserRole(user.getUser_key(), Code.UserType.SUPER) && ObjectUtil.isNotEmpty(obj.getNode_id()) ){
				// 管理员要查看，信息
				;
			}else{
				obj.setUser_id(user.getId());				
			}
			resultMap = service.selectPageList("IotSensorInfo.selectPage",getPageBean(paged,pageSize), obj);															
		} catch (Exception e) {
			exception(e,resultMap, obj);
		}
		return getModelAndView(response, resultMap);
	}
	
	/**
	 * 插入
	 * @param response
	 * @param 
	 * @return
	 */
	@RequestMapping(method = RequestMethod.POST, value = RequestURLIOT.SensorInfo.SENSOR_INFO )
	public ModelAndView save(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestBody IotSensorInfoBO obj ) {
		Map<String, Object> resultMap = getResultMap();
		try {
			UserInfoBO user = getUserInfoByUserKey(userKey);
			// 增加传感器的状态
			obj.setIot_sensor_status(CodeIot.DEVICE_STATUS.UNCONTECT);
			// 部分服务器不兼容，mysql数据库时间自动填充
			obj.setRegister_time(new Date());
			if( ObjectUtil.isEmpty(obj.getSdata()) ){
				obj.setSdata(0f);				
			}
			obj.setRequest_sdata(0f);
			obj.setMtime(new Date());
			IotSensorInfoBO infoBO = (IotSensorInfoBO)getData(service.selectOne("IotSensorInfo.selectMaxCode",obj.getEquip_code(),obj.getTarget_type()));
			if(ObjectUtil.isNotEmpty(infoBO)) {
				String str = infoBO.getTarget_code().substring(infoBO.getTarget_code().length()-3);
				int num = Integer.parseInt(str) + 1;
				obj.setTarget_code(obj.getEquip_code() + obj.getTarget_type()+ String.format("%03d", num));
			} else {
				obj.setTarget_code(obj.getEquip_code() + obj.getTarget_type()+ "001");
			}
			resultMap = service.insert("IotSensorInfo.insert", obj) ;
			if(isOk(resultMap)){
				ProCacheUtil.addCache(CacheName.SENSORINFO, obj.getId().toString(), obj);
				ProCacheUtil.addCache(CacheName.SENSORINFO_NSP, obj.getNode_id()+"-"+obj.getSensor_device_id()+"-"+obj.getPort_id(), obj);
				
				// 这边获取到网关的缓存信息,如果是modbus设备，则更新下发的缓存
				IotNodeInfoBO nodeDt = ProCacheUtil.getCache(CacheName.NODEINFO, obj.getNode_id().toString());
				if(ObjectUtil.isNotEmpty(nodeDt)){
					if(  nodeDt.getIot_node_type()+0 == 83 && nodeDt.getIot_protocal_category().contains("ProtocalModbus")  ){
						// 修改网关信息后，则设置设备重新连接  TCP协议
						ProtocolUtil.sendGatewayRestart(nodeDt) ;											
					}
				}
			}
		} catch (Exception e) {
			exception(e,resultMap, obj);
		}
		return getModelAndView(response, resultMap);
	}
	
	/**
	 * 查询单个
	 * @param response
	 * @param id
	 * @return
	 */
	@RequestMapping(method = RequestMethod.GET, value = RequestURLIOT.SensorInfo.SENSOR_INFO)
	public ModelAndView selectOne(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestParam Integer id ) {
		Map<String, Object> resultMap = getResultMap();
		try {
			resultMap = service.selectOne("IotSensorInfo.selectOne", new IotSensorInfoBO(id)) ;
		} catch (Exception e) {
			exception(e,resultMap, id);
		}
		return getModelAndView(response, resultMap);
	}
	
	/**
	 * 传感器数据上传 realtime SENSOR_VALUE 批量数据上传
	 */
	@RequestMapping(method = RequestMethod.PUT, value = RequestURLIOT.SensorInfo.SENSORS_VALUE)
	public ModelAndView updateSensorsValue(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestBody List<IotSensorInfoBO> iotSensors ) {
		Map<String, Object> resultMap = getResultMap();
		try {
			for(IotSensorInfoBO obj:iotSensors){
				IotSensorInfoBO tmp = new IotSensorInfoBO();
				tmp.setSdata(obj.getSdata());
				if(ObjectUtil.isNotEmpty(obj.getStr_sdata())){
					tmp.setStr_sdata(obj.getStr_sdata());
				}
				tmp.setSensor_device_id(obj.getSensor_device_id());
				tmp.setPort_id(obj.getPort_id());
				tmp.setRequest_sdata(obj.getRequest_sdata());
				tmp.setDevice_code(obj.getDevice_code());
				// 如果没有上传mtime，则用当前时间为mtime
				if(ObjectUtil.isEmpty(obj.getMtime())){
					tmp.setMtime(new Date());
				}else{
					tmp.setMtime(obj.getMtime());
				}
				// 传感器实时数据上传
				resultMap = iotSensorInfoService.updateRealTimeData(tmp);			
			}
			
			// 发送mqtt消息给前端
			if( ObjectUtil.isNotEmpty(iotSensors) ){
				IotNodeInfoBO iotNodeInfo = ProCacheUtil.getCache(CacheName.NODEINFO_DEVICECODE, iotSensors.get(0).getDevice_code());
				if(ObjectUtil.isNotEmpty(iotNodeInfo)){
					String scene_id = ProCacheUtil.getCache(CacheName.SCENE_IPDATE_FLAG , "scene_" +  iotNodeInfo.getScene_id() );
					if(ObjectUtil.isNotEmpty(scene_id)){
						MqttService.pubMessage( "1", "/scene/update/"+  iotNodeInfo.getScene_id() );				
					}
					String node_id = ProCacheUtil.getCache(CacheName.SCENE_IPDATE_FLAG , "node_" + iotNodeInfo.getId()  );
					if(ObjectUtil.isNotEmpty(node_id)){
						MqttService.pubMessage( "1", "/node/update/"+  iotNodeInfo.getId() );
					}
				}
			}
		} catch (Exception e) {
			exception(e,resultMap, iotSensors);
		}
		return getModelAndView(response, resultMap);
	}
	
	/**
	 * 传感器数据上传 realtime SENSOR_VALUE
	 */
	@RequestMapping(method = RequestMethod.PUT, value = RequestURLIOT.SensorInfo.SENSOR_VALUE)
	public ModelAndView updateSensorValue(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestBody IotSensorInfoBO obj ) {
		Map<String, Object> resultMap = getResultMap();
		try {
			IotSensorInfoBO tmp = new IotSensorInfoBO();
			tmp.setSdata(obj.getSdata());
			tmp.setSensor_device_id(obj.getSensor_device_id());
			tmp.setPort_id(obj.getPort_id());
			if(ObjectUtil.isNotEmpty(obj.getStr_sdata())){
				tmp.setStr_sdata(obj.getStr_sdata());
			}
			tmp.setRequest_sdata(obj.getRequest_sdata());
			tmp.setDevice_code(obj.getDevice_code());
			// 如果没有上传mtime，则用当前时间为mtime
			if(ObjectUtil.isEmpty(obj.getMtime())){
				tmp.setMtime(new Date());
			}else{
				tmp.setMtime(obj.getMtime());
			}
			// 传感器实时数据上传
			resultMap = iotSensorInfoService.updateRealTimeData(tmp);
			
			// webscoket mqtt 发送数据
			if( ObjectUtil.isNotEmpty(obj) ){
				IotNodeInfoBO iotNodeInfo = ProCacheUtil.getCache(CacheName.NODEINFO_DEVICECODE, obj.getDevice_code());
				if(ObjectUtil.isNotEmpty(iotNodeInfo)){
					String scene_id = ProCacheUtil.getCache(CacheName.SCENE_IPDATE_FLAG , "scene_" + iotNodeInfo.getScene_id() );
					if(ObjectUtil.isNotEmpty(scene_id)){
						MqttService.pubMessage( "1", "/scene/update/"+  iotNodeInfo.getScene_id() );				
					}
					String node_id = ProCacheUtil.getCache(CacheName.SCENE_IPDATE_FLAG , "node_" + iotNodeInfo.getId() );
					if(ObjectUtil.isNotEmpty(node_id)){
						MqttService.pubMessage( "1", "/node/update/"+  iotNodeInfo.getId() );
					}
				}
			}
		} catch (Exception e) {
			exception(e,resultMap, obj);
		}
		return getModelAndView(response, resultMap);
	}
	
	/**
	 * 实时更新传感器数值( 执行器请求状态改变 )
	 * @param response
	 * @param obj
	 * @return
	 */
	@RequestMapping(method = RequestMethod.PUT, value = RequestURLIOT.SensorInfo.SENSOR_CONTROL_VALUE)
	public ModelAndView updateSensorControlValue(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestBody IotSensorInfoBO obj ) {
		Map<String, Object> resultMap = getResultMap();
		try {
			UserInfoBO user = getUserInfoByUserKey(userKey);
			IotSensorInfoBO tmp = new IotSensorInfoBO();
			if(ObjectUtil.isNotEmpty(obj.getId())){
				tmp.setId(obj.getId());
				tmp.setSdata(obj.getSdata());
				tmp.setRequest_sdata(obj.getRequest_sdata());
				tmp.setUser_id(user.getId());
				// 发送消息给LPM
				if( ProtocolUtil.sendControlSensorCommand(obj) >-1){
					resultMap = service.update("IotSensorInfo.update", tmp) ;					
				}else{
					putStatusCode(resultMap, CodeIot.DEVICE_STATUS.OFFLINE);
				}
			}else{
				putStatusCode(resultMap, Code.ResponseCode.SystemCode.PARAM_ERROR);
			}
		} catch (Exception e) {
			exception(e,resultMap, obj);
		}
		return getModelAndView(response, resultMap);
	}
	
	/**
	 * 参数更新
	 * 参数下发的时候，不清楚配置是否能配置，所以数据库中显示当前确认过配置数据
	 */
	@RequestMapping(method = RequestMethod.PUT, value = RequestURLIOT.SensorInfo.SENSOR_PARAM_SETTING_REPLAY)
	public ModelAndView sensorParamSuccessReplay(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestBody IotSensorInfoBO obj ) {
		Map<String, Object> resultMap = getResultMap();
		try {
			// 通过deviceid,sensorDeviceid,portid 
			IotNodeInfoBO nodeTmp = ProCacheUtil.getCache(CacheName.NODEINFO_DEVICECODE, obj.getDevice_code());
			IotSensorInfoBO tmp = ProCacheUtil.getCache(CacheName.SENSORINFO_NSP,
					nodeTmp.getId()+"-"+obj.getSensor_device_id()+"-"+obj.getPort_id() );
			tmp = ProCacheUtil.getCache(CacheName.SENSOR_PARAM_SETTING, tmp.getId().toString()) ;
			if(ObjectUtil.isNotEmpty(tmp)){
				resultMap = service.update("IotSensorInfo.update", tmp) ;
				if(isOk(resultMap)){
					ProCacheUtil.removeCache(CacheName.SENSOR_PARAM_SETTING, tmp.getId().toString());
				}
			}
		}catch (Exception e) {
			exception(e,resultMap, obj);
		}
		return getModelAndView(response, resultMap);
	}
	
	
	/**
	 * 参数下发
	 * @param response
	 * @param userKey
	 * @param obj
	 * @return
	 */
	@RequestMapping(method = RequestMethod.PUT, value = RequestURLIOT.SensorInfo.SENSOR_PARAM_SETTING_DOWN)
	public ModelAndView updateSensorParamDown(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestBody IotSensorInfoBO obj ) {
		Map<String, Object> resultMap = getResultMap();
		try {
			// 目前暂时，先把数据存起来，以后要做缓存处理的；
			UserInfoBO user = getUserInfoByUserKey(userKey);
			IotSensorInfoBO tmp = new IotSensorInfoBO();
			if(ObjectUtil.isNotEmpty(obj.getId())){
				tmp.setId(obj.getId());
				tmp.setSdata(obj.getSdata());
				tmp.setUser_id(user.getId());
				// 这边要处理的
				tmp.setData_type(-1);
				tmp.setMtime(new Date());
				// 发送消息给LPM
				if( ProtocolUtil.sendSensorParamDown(obj) >-1){
					ProCacheUtil.addCache(CacheName.SENSOR_PARAM_SETTING, obj.getId()+"", tmp );
				}else{
					putStatusCode(resultMap, CodeIot.DEVICE_STATUS.OFFLINE);
				}
			}else{
				putStatusCode(resultMap, Code.ResponseCode.SystemCode.PARAM_ERROR);
			}
		}catch (Exception e) {
			exception(e,resultMap, obj);
		}
		return getModelAndView(response, resultMap);
	}
	/**
	 * 设备参数读取
	 * @param response
	 * @param userKey
	 * @param obj
	 * @return
	 */
	@RequestMapping(method = RequestMethod.PUT, value = RequestURLIOT.SensorInfo.SENSOR_PARAM_SETTING_READ)
	public ModelAndView updateSensorParamRead(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestBody IotSensorInfoBO obj ) {
		Map<String, Object> resultMap = getResultMap();
		try {
			if(ObjectUtil.isNotEmpty(obj.getId())){
				// 发送消息给LPM
				if( ProtocolUtil.sendSensorParamRead(obj) >-1){
										
				}else{
					putStatusCode(resultMap, CodeIot.DEVICE_STATUS.OFFLINE);
				}
			}else{
				putStatusCode(resultMap, Code.ResponseCode.SystemCode.PARAM_ERROR);
			}
		}catch (Exception e) {
			exception(e,resultMap, obj);
		}
		return getModelAndView(response, resultMap);
	}
	
	/**
	 * 更新
	 * @param response
	 * @param obj
	 * @return
	 */
	@RequestMapping(method = RequestMethod.PUT, value = RequestURLIOT.SensorInfo.SENSOR_INFO)
	public ModelAndView update(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestBody IotSensorInfoBO obj ) {
		Map<String, Object> resultMap = getResultMap();
		try {
			UserInfoBO user = getUserInfoByUserKey(userKey);
			obj.setUser_id(user.getId());
			resultMap = service.update("IotSensorInfo.update", obj) ;
			if(isOk(resultMap)){
				ProCacheUtil.addCache(CacheName.SENSORINFO, obj.getId().toString(), obj);
				ProCacheUtil.addCache(CacheName.SENSORINFO_NSP, obj.getNode_id()+"-"+obj.getSensor_device_id()+"-"+obj.getPort_id(), obj);
				
				// 这边获取到网关的缓存信息,如果是modbus设备，则更新下发的缓存
				IotNodeInfoBO nodeDt = ProCacheUtil.getCache(CacheName.NODEINFO, obj.getNode_id().toString());
				if(ObjectUtil.isNotEmpty(nodeDt)){
					if(  nodeDt.getIot_node_type()+0 == 83 &&  nodeDt.getIot_protocal_category().contains("ProtocalModbus")   ){
						// 修改网关信息后，则设置设备重新连接  TCP协议
						ProtocolUtil.sendGatewayRestart(nodeDt) ;											
					}
				}
				
			}
		} catch (Exception e) {
			exception(e,resultMap, obj);
		}
		return getModelAndView(response, resultMap);
	}
	
	/**
	 * 删除
	 * @param response
	 * @param id
	 * @return
	 */
	@RequestMapping(method = RequestMethod.DELETE, value = RequestURLIOT.SensorInfo.SENSOR_INFO)
	public ModelAndView delete(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestParam Integer id ) {
		Map<String, Object> resultMap = getResultMap();
		try {
			IotSensorInfoBO obj = new IotSensorInfoBO();
			if(ObjectUtil.isEmpty(id)){
				putStatusCode(resultMap, Code.ResponseCode.SystemCode.PARAM_ERROR);
			}else{
				obj.setId(id);
				obj.setDelete_flag(Constants.DELETE.YES);
				obj.setMtime(new Date());
				resultMap = service.update("IotSensorInfo.update", obj) ;		
				if(isOk(resultMap)){
					ProCacheUtil.removeCache(CacheName.SENSORINFO, obj.getId().toString());
					ProCacheUtil.removeCache(CacheName.SENSORINFO_NSP, obj.getNode_id()+"-"+obj.getSensor_device_id()+"-"+obj.getPort_id());
				}
			}
		} catch (Exception e) {
			exception(e,resultMap, id);
		}
		return getModelAndView(response, resultMap);
	}
	
	/**
	 * 获取定位传感器数据
	 */
	@RequestMapping(method = RequestMethod.POST, value = RequestURLIOT.SensorInfo.SENSOR_GPS_VALUE)
	public ModelAndView selectAllSensorGpsInfo(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestBody IotSensorInfoBO obj) {
		Map<String, Object> resultMap = getResultMap();
		try {
			UserInfoBO user = getUserInfoByUserKey(userKey);
			obj.setUser_id(user.getId());
			resultMap = service.selectList("IotSensorInfo.selectLonLatSensorInfo", obj);												
		} catch (Exception e) {
			exception(e,resultMap, obj);
		}
		return getModelAndView(response, resultMap);
	}
	
	
	/**
	 * 根据设备号，设备id和端口id，查询单个传感器的实时数据
	 */
	@RequestMapping(method = RequestMethod.POST, value = RequestURLIOT.SensorInfo.SENSOR_REALTIME_VALUE)
	public ModelAndView selectOneSensorBydev_sev_pid(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestBody IotSensorInfoBO obj) {
		Map<String, Object> resultMap = getResultMap();
		try {
			IotNodeInfoBO iotNodeInfo = ProCacheUtil.getCache(CacheName.NODEINFO_DEVICECODE, obj.getDevice_code());
			if(ObjectUtil.isNotEmpty(iotNodeInfo)){
				IotSensorInfoBO sensorInfo = ProCacheUtil.getCache(CacheName.SENSORINFO_NSP, 
						iotNodeInfo.getId()+"-"+obj.getSensor_device_id()+"-"+obj.getPort_id());
				putData(resultMap, sensorInfo);
			}else{
				putStatusCode(resultMap, Code.ResponseCode.SystemCode.NO_DATA) ;
			}
		} catch (Exception e) {
			exception(e,resultMap, obj);
		}
		return getModelAndView(response, resultMap);
	}
	
	/**
	 * 查询单个设备传感器列表数据
	 * @param response
	 * @param userKey
	 * @param obj
	 * @return
	 */
	@RequestMapping(method = RequestMethod.POST, value = RequestURLIOT.SensorInfo.NODE_REALTIME_VALUE)
	public ModelAndView selectNodeSensorList(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestBody IotSensorInfoBO obj) {
		Map<String, Object> resultMap = getResultMap();
		try {
			IotNodeInfoBO iotNodeInfo = ProCacheUtil.getCache(CacheName.NODEINFO_DEVICECODE, obj.getDevice_code());
			if(ObjectUtil.isNotEmpty(iotNodeInfo)){
				IotSensorInfoBO dt = new IotSensorInfoBO() ;
				dt.setNode_id(iotNodeInfo.getId());
				resultMap = service.selectList("IotSensorInfo.selectPage",  dt ) ;
			}else{
				putStatusCode(resultMap, Code.ResponseCode.SystemCode.NO_DATA) ;
			}
		} catch (Exception e) {
			exception(e,resultMap, obj);
		}
		return getModelAndView(response, resultMap);
	}
	
	/**
	 * 控制命令下发
	 * @param response
	 * @param userKey
	 * @param obj
	 * @return
	 */
	@RequestMapping(method = RequestMethod.POST, value = RequestURLIOT.SensorInfo.SENSOR_REALTIME_CONTROL)
	public ModelAndView sendSensorCmd(HttpServletResponse response, 
			@RequestHeader(value = ResultMapUtils.USER_KEY, required = true) String userKey ,
			@RequestBody IotSensorInfoBO obj) {
		Map<String, Object> resultMap = getResultMap();
		try {
			IotNodeInfoBO iotNodeInfo = ProCacheUtil.getCache(CacheName.NODEINFO_DEVICECODE, obj.getDevice_code());
			if(ObjectUtil.isNotEmpty(iotNodeInfo)){
				IotSensorInfoBO sensorInfo = ProCacheUtil.getCache(CacheName.SENSORINFO_NSP, 
						iotNodeInfo.getId()+"-"+obj.getSensor_device_id()+"-"+obj.getPort_id());
				
				UserInfoBO user = getUserInfoByUserKey(userKey);
				IotSensorInfoBO tmp = new IotSensorInfoBO();
				if(ObjectUtil.isNotEmpty(sensorInfo.getId())){
					tmp.setId(sensorInfo.getId());
					tmp.setSdata(sensorInfo.getSdata());
					tmp.setRequest_sdata(obj.getRequest_sdata());
					tmp.setUser_id(user.getId());
					// 发送消息给LPM
					if( ProtocolUtil.sendControlSensorCommand(tmp) >-1){
						resultMap = service.update("IotSensorInfo.update", tmp) ;					
					}else{
						putStatusCode(resultMap, CodeIot.DEVICE_STATUS.OFFLINE);
					}
				}else{
					putStatusCode(resultMap, Code.ResponseCode.SystemCode.PARAM_ERROR);
				}
				
				
			}else{
				putStatusCode(resultMap, Code.ResponseCode.SystemCode.NO_DATA) ;
			}
		} catch (Exception e) {
			exception(e,resultMap, obj);
		}
		return getModelAndView(response, resultMap);
	}
	
}
